package com.wondersgroup.hs.mobile.report.support.dataSource;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fr.base.FRContext;
import com.fr.base.Parameter;
import com.fr.data.AbstractTableData;
import com.fr.general.data.TableDataException;
import com.fr.stable.ParameterProvider;
import com.wondersgroup.hs.mobile.report.support.ReflectUtils;
import com.wondersgroup.hs.mobile.report.support.exception.StatusAndMessageError;

import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;

/**
 * Created by zarra on 2016/12/28.
 */
public abstract class RestServiceDS<REQ,RSP> extends AbstractTableData {

    Class<REQ> reqClass;
    Class<RSP> rspClass;

    List<RSP> data = null;

    PropertyDescriptor[] requestPropertyDescriptors = null;
    PropertyDescriptor[] responsePropertyDescriptors = null;

    public RestServiceDS(){
        Type superclass = getClass().getGenericSuperclass();
        Type reqType = ((ParameterizedType)superclass).getActualTypeArguments()[0];
        Type rspType = ((ParameterizedType)superclass).getActualTypeArguments()[1];

        reqClass = (Class<REQ>) reqType;
        rspClass = (Class<RSP>) rspType;

        init();
    }

    public void init(){
        requestPropertyDescriptors  = ReflectUtils.getPropertyDescriptors(reqClass);
        responsePropertyDescriptors = ReflectUtils.getPropertyDescriptors(rspClass);

        List<Parameter> parameters = new LinkedList<>();

        for (PropertyDescriptor p : requestPropertyDescriptors){
            parameters.add(new Parameter(p.getDisplayName(),null));
        }

        setDefaultParameters(parameters.toArray(new Parameter[0]));
    }

    public ParameterProvider fetchParameter(String name){
        ParameterProvider parameterProvider = null;

        for (ParameterProvider p : parameters){
            if (p.getName().equals(name)){
                parameterProvider = p;
                break;
            }
        }
        return parameterProvider;
    }

    public void fetchData(){
        if (data != null) return;
        try {
            REQ req = reqClass.newInstance();
            FRContext.getLogger().log(Level.INFO, "after newInstance");
            for (PropertyDescriptor p : requestPropertyDescriptors){
                String name = p.getDisplayName();
                Class<?> type = p.getPropertyType();
                ParameterProvider parameter = fetchParameter(name);
                Object value = parameter.getValue();
                if (value!=null) {
                    String stringValue = value.toString();
                    if (stringValue.length() > 0) {
                        if (Collection.class.isAssignableFrom(type)) {

                            ObjectMapper om = new ObjectMapper();
                            value = om.readValue(stringValue, type);
                        }
                        if (value != null) {
                            FRContext.getLogger().log(Level.INFO, "set property:" + p.getDisplayName());
                            FRContext.getLogger().log(Level.INFO, "value type:" + value.getClass().getName());
                            if (value == null) {
                                FRContext.getLogger().log(Level.INFO, "value:null");
                            }
                            FRContext.getLogger().log(Level.INFO, "value:" + value);
                            p.getWriteMethod().invoke(req, value);
                        }
                    }
                }
            }

            data = new LinkedList<>();
            data.addAll(fetchDataPrivate(req));


        }  catch (Exception e) {
            throw new StatusAndMessageError(-9,e);
        }
    }

    public abstract Collection<RSP> fetchDataPrivate(REQ req) throws Exception;

    @Override
    public int getColumnCount() throws TableDataException {
        return responsePropertyDescriptors.length;
    }

    @Override
    public String getColumnName(int i) throws TableDataException {
        PropertyDescriptor propertyDescriptor = responsePropertyDescriptors[i];
        return propertyDescriptor.getDisplayName();
    }

    @Override
    public int getRowCount() throws TableDataException {
        fetchData();
        return data.size();
    }

    @Override
    public Object getValueAt(int i, int j) {
        fetchData();
        RSP rsp = data.get(i);

        PropertyDescriptor propertyDescriptor = responsePropertyDescriptors[j];

        if (rsp == null) return  null;
        else
            return ReflectUtils.getProperty(rsp,propertyDescriptor);
    }


}
